package indi.mozping.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.BasicDBList;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Array;
import java.text.ParseException;
import java.util.*;

/**
 * @ClassName StrUtil
 * @Description String类型的工具类
 * @Author mozping
 * @Date 16:19
 * @Version 1.0
 */
public class StrUtil {

    private static final Logger LOG = LoggerFactory.getLogger(StrUtil.class);

    private static final String FEATURE = "FEATURE";
    private static final String FACE_FEATURE = "face_feature";
    private static final int THROULD_LENGTH = 500;
    private static final String TIME = "time";
    private static final String TIME_UPCASE = "Time";
    private static final String CONDITION_GROUP = "ConditionGroup_";
    private static final String YEAR = "year";
    private static final String MONTH = "month";
    private static final String DAY = "day";
    private static final String HOUR = "hour";


    public static List<Object> getTimeGroupList(String timeGroupType) {
        return getTimeGroupList(timeGroupType, "time");
    }

    public static List<Object> getTimeGroupList(String timeGroupType, String fieldName) {
        String filed = "$" + fieldName;
        if (timeGroupType == null || StrUtil.isBlank(timeGroupType) || "min".equalsIgnoreCase(timeGroupType)) {
            return Arrays.asList(filed, 0, 16);
        } else if (HOUR.equalsIgnoreCase(timeGroupType)) {
            return Arrays.asList(filed, 0, 13);
        } else if (DAY.equalsIgnoreCase(timeGroupType)) {
            return Arrays.asList(filed, 0, 10);
        } else if (MONTH.equalsIgnoreCase(timeGroupType)) {
            return Arrays.asList(filed, 0, 7);
        } else if (YEAR.equalsIgnoreCase(timeGroupType)) {
            return Arrays.asList(filed, 0, 4);
        } else {
            return Arrays.asList(filed, 0, 16);
        }
    }

    /**
     * @param key  in条件对应的字段
     * @param list list集合，集合中是in条件的所属值集合
     * @Description: 获取Mongodb条件的合法in条件表达式
     * @date 2019/1/12 14:47
     * eg：list是1,2,3,4,5, 那么返回的BasicDBList对象就包含1,2,3,4,5 这里考虑了字符串和数值型转换的问题，可考虑了_id对象的问题
     */
    public static BasicDBList getInBasicDBList(String key, List<String> list) {

        BasicDBList values = new BasicDBList();
        for (String val : list) {
            //判断是否为int,如果是int就把int值加到in条件里面去，否则查不到；如果不是int就是字符串，默认当做字符串加入就好
            if ("_id".equalsIgnoreCase(key)) {
                //_id的情况
                values.add(new ObjectId(val));
            } else {
                if (StrUtil.isInt32(val)) {
                    values.add(Integer.valueOf(val));
                }
                values.add(val);
            }
        }
        return values;
    }

    /**
     * @param obj 对象
     * @Description: 获取合法的mongodb索引的标识，合法标识只有2种取值，1和-1
     * @date 2019/1/12 14:45
     */
    public static int getMongoIndexFlag(Object obj) {
        try {
            int i = Integer.parseInt(obj.toString());
            return i > 0 ? 1 : -1;
        } catch (Exception e) {
            try {
                double d = Double.parseDouble(obj.toString());
                return d > 0 ? 1 : -1;
            } catch (Exception ex) {
                return 1;
            }
        }
    }

    /**
     * 去除集合中重复的数据：
     * 重复数据的定义：除了主键之外，其他的键对应的值完全一样的，则定义为重复数据
     * distinct是一个json对象，
     * {
     * "open":"true/false"，
     * "field":"tid"
     * }
     */
    public static JSONArray getDistinctJsonArray(JSONArray arrOriginal, JSONObject distinct) {
        List<String> keyList = new ArrayList<>();
        keyList.add("tid");
        if (arrOriginal == null || arrOriginal.isEmpty()) {
            return arrOriginal;
        }
        //不需要去重直接返回
        if (distinct == null || distinct.isEmpty() || !"true".equalsIgnoreCase(distinct.getString("open"))) {
            return arrOriginal;
        }
        ArrayList<Integer> indexArr = new ArrayList<>();
        for (int i = 1; i < arrOriginal.size(); i++) {
            for (int j = 0; j < i; j++) {
                if (isEquals(arrOriginal.get(j), arrOriginal.get(i), keyList)) {
                    //标记为重复
                    indexArr.add(i);
                }
            }
        }
        for (Integer i : indexArr) {
            arrOriginal.remove((int) i);
        }
        return arrOriginal;
    }


    /**
     * @param obj1    待比较的json
     * @param obj2    待比较的json
     * @param keyList 需要比较的字段
     * @Description: 比较两个json是否相等，需要比较的字段均相等，就算相等
     * @date 2019/1/12 19:31
     */
    public static boolean isEquals(Object obj1, Object obj2, List<String> keyList) {
        if (!(obj1 instanceof JSONObject) || !(obj2 instanceof JSONObject)) {
            return obj1.equals(obj2);
        }
        JSONObject jsonObject1 = (JSONObject) obj1;
        JSONObject jsonObject2 = (JSONObject) obj2;
        for (String key : keyList) {
            if (jsonObject1.containsKey(key) && jsonObject2.containsKey(key)) {
                Object objTmp1 = jsonObject1.get(key);
                Object objTmp2 = jsonObject2.get(key);
                if (!objTmp2.equals(objTmp1)) {
                    return false;
                }
            }
        }

        return true;
    }


    /**
     * @param addParam 新增请求参数对象
     * @Description: 打印新增请求日志
     * @date 2019/1/12 19:32
     */
    public static void logAddParams(JSONObject addParam) {
        JSONObject param = JSONObject.parseObject(addParam.toString());
        JSONArray arrNew = new JSONArray();
        if (param.containsKey(GlobalConsts.DATAS)) {
            JSONArray arr = param.getJSONArray(GlobalConsts.DATAS);
            for (Object obj : arr) {
                String tid = ((JSONObject) obj).getString(GlobalConsts.TID);
                arrNew.add(GlobalConsts.TID + " : " + tid);
            }
        }
        arrNew.add("operator:" + addParam.getString(GlobalConsts.OPERATOR));
        arrNew.add("targetType:" + addParam.getString(GlobalConsts.TYPE));
        LOG.info("Add params:" + arrNew);
    }


    /**
     * @param list 对象列表
     * @Description: 判断多个对象是否包含空对象，只要有一个不为空则返回true，全部为空则返回false
     * @date 2019/1/12 15:28
     * 全部为空返回false，反之返回true
     */
    public static boolean isNotNullOrEmpty(Object... list) {
        if (list == null || list.length == 0) {
            return false;
        }
        for (Object obj : list) {
            if (!isEmpty(obj)) {
                return true;
            }
        }
        return false;
    }


    /**
     * @param retJson 返回的json对象
     * @param docJson 原对象
     * @param retKeys 需要提取的key
     * @Description: 提取返回参数，从原对象中提取需要返回的字段到需要返回的json对象
     * @date 2019/1/12 19:34
     */
    public static JSONObject getRetunJson(JSONObject retJson, JSONObject docJson, List<String> retKeys) {

        if (null != retKeys && !retKeys.isEmpty()) {
            for (int j = 0; j < retKeys.size(); j++) {
                String key = (String) retKeys.get(j);
                if (retJson.containsKey(key)) {
                    continue;
                } else {
                    retJson.put(key, docJson.get(key));
                }
            }
        }

        return retJson;
    }


    /**
     * @param pageParams 分页参数
     * @Description: 提取分页参数，从分页参数对象提取合法的分页参数并返回
     * @date 2019/1/12 19:35
     */
    public static Map<String, Integer> getPageParams(JSONObject pageParams) {
        HashMap<String, Integer> pageMap = new HashMap<>(GlobalConsts.SIZE_OF_FOUR);
        pageMap.put(GlobalConsts.PAGE_NEED_TOTAL, 1);
        if (pageParams == null || !pageParams.containsKey(GlobalConsts.PAGE_NO) || !pageParams.containsKey(GlobalConsts.PAGE_SIZE)) {
            pageMap.put(GlobalConsts.PAGE_NO, GlobalConsts.DEFAULT_PAGE_NO);
            pageMap.put(GlobalConsts.PAGE_SIZE, GlobalConsts.DEFAULT_PAGE_SIZE);
            return pageMap;
        }

        pageMap.put(GlobalConsts.PAGE_NO, pageParams.getIntValue(GlobalConsts.PAGE_NO));
        pageMap.put(GlobalConsts.PAGE_SIZE, pageParams.getIntValue(GlobalConsts.PAGE_SIZE));
        if (pageParams.containsKey(GlobalConsts.PAGE_NEED_TOTAL)) {
            int tmp = pageParams.getIntValue(GlobalConsts.PAGE_NEED_TOTAL);
            pageMap.put(GlobalConsts.PAGE_NEED_TOTAL, tmp == 1 ? 1 : 0);
        }

        return pageMap;
    }

    /**
     * 获取A.B形式的B的部分作为key，
     */
    public static String getSubKey(String str, int index) {
        if (!str.contains(".")) {
            return str;
        }
        String[] strArr = str.split("\\.");
        if (index == 1) {
            return strArr[1];
        }
        return strArr[0];
    }

    /**
     * 校验条件查询时的key 的合法性，合法返回true，非法返回false
     */
    public static boolean isConditionGroupValid(Set<String> keySet) {
        return isConditionGroupValid(keySet, CONDITION_GROUP);
    }

    public static boolean isConditionGroupValid(Set<String> keySet, String suffix) {
        int keyCount = keySet.size() - 1;
        for (int i = 1; i <= keyCount; i++) {
            String tmpKey = suffix.concat(String.valueOf(i));
            if (!keySet.contains(tmpKey)) {
                return false;
            }
        }
        return true;
    }


    /**
     * @param str key
     * @Description: 判断一个key是否是描述时间的, 如果key包含time或者Time则认为是
     * @date 2019/1/12 19:37
     */
    public static boolean isTimeKey(String str) {
        if (str == null || str.length() == 0) {
            return false;
        }
        return str.contains(TIME) || str.contains(TIME_UPCASE);
    }

    /**
     * @param key   key
     * @param value value
     * @Description: 判断一个value是否是描述时间的, 如果key包含time或者Time则认为是
     * @date 2019/1/12 19:37
     */
    public static boolean isTimeKeyValue(String key, Object value) {
        if (key == null || value == null) {
            return false;
        }
        if (!isTimeKey(key) || value.toString().length() > 30) {
            return false;
        }
        try {
            DateUtil.convertStringToDate(GlobalConsts.DEFAULT_TIME_PATTERN, value.toString().trim());
        } catch (ParseException e) {
            return false;
        }
        return true;
    }


    public static JSONObject convertToStatisticResult(JSONObject itemJson) throws ParseException {
        return convertToStatisticResult(itemJson, false);
    }

    public static JSONObject convertToStatisticResult(JSONObject itemJson, boolean isComplex) throws ParseException {

        JSONObject obj = new JSONObject();
        JSONObject jsonObj = itemJson.getJSONObject("_id");
        StringBuilder statisticalItems = new StringBuilder();
        StringBuilder statisticalValue = new StringBuilder();

        for (Map.Entry entry : jsonObj.entrySet()) {
            statisticalItems.append(entry.getKey()).append("#");
            //这里对时间做下处理，在数据库中的是UTC时间，进行时间的截取做分组之后，变成了字符串，相当于保留了UTC时间字符串的前面一部分，
            //这里转成东八区时间，字符串的位数还是保存不变
            //如果key是time，那么对应的value就需要改一下
            if (GlobalConsts.TIME.equalsIgnoreCase(entry.getKey().toString())) {
                statisticalValue.append(DateUtil.utcStrToLocal(entry.getValue().toString())).append("#");
            } else {
                statisticalValue.append(entry.getValue()).append("#");
            }
        }

        obj.put("statisticalItem", statisticalItems.substring(0, statisticalItems.length() - 1));
        obj.put("statisticalValue", statisticalValue.substring(0, statisticalValue.length() - 1));

        if (!isComplex) {
            obj.put("statisticalResult", itemJson.get("num_tutorial"));
        }

        if (isComplex) {
            for (String k : itemJson.keySet()) {
                if (!"_id".equalsIgnoreCase(k)) {
                    //这里如果是时间类型，需要做转换
                    Object value = itemJson.get(k);
                    if (value instanceof JSONObject && ((JSONObject) value).containsKey("$date")) {
                        long millisecond = ((JSONObject) value).getLong("$date");
                        obj.put(k, DateUtil.getDateStrByUnixTime(millisecond, GlobalConsts.DEFAULT_TIME_PATTERN));
                    } else if (value instanceof JSONArray && value.toString().contains("oid")) {
                        JSONArray jsonArrayTmp = (JSONArray) value;
                        JSONArray ret = new JSONArray();
                        for (Object o : jsonArrayTmp) {
                            if (o instanceof JSONObject && ((JSONObject) o).containsKey("$oid")) {
                                //如果key是_id，那么返回的是一个对象，需要吧对象里面的数据库ObjectId取出，返回
                                String oid = ((JSONObject) o).getString("$oid");
                                ret.add(oid);
                            }
                        }
                        if (!ret.isEmpty()) {
                            obj.put(k, ret);
                        }
                    } else {
                        obj.put(k, value);
                    }
                }
            }
        }
        return obj;
    }


    /**
     * 用指定的拼接符连接字符串集合
     *
     * @param list 字符串结合
     * @param str  连接符
     * @return java.lang.String
     */
    public static String concatStringArrWithStr(List<String> list, String str) {

        if (list == null || list.isEmpty()) {
            return "";
        }
        if (list.size() == 1) {
            return list.get(0);
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < list.size() - 1; i++) {
            sb.append(list.get(i)).append(str);
        }
        //连接最后一个
        sb.append(list.get(list.size() - 1));

        return sb.toString();
    }


    /**
     * 消息处理方法
     * 引擎传的消息过长，打印日志时，去除特征值不打印
     *
     * @param str 消息字符串
     * @return java.lang.String 处理后的字符串
     */
    public static String removeFeature(String str) {
        String result = str;
        int length = str.length();
        int indexFlag;
        int indexBegin;
        int indexEnd;
        if (length < THROULD_LENGTH) {
            return result;
        }
        if (result.indexOf(FEATURE) == -1) {
            return result;
        }

        for (int flag = 0; flag < length && flag != -1; ) {
            indexFlag = result.indexOf(FEATURE, flag);
            indexBegin = result.indexOf('[', indexFlag);
            indexEnd = result.indexOf(']', indexFlag);
            result = result.substring(0, indexBegin + 1) + result.substring(indexEnd);
            flag = result.indexOf(FEATURE, indexBegin);
        }
        return result;
    }


    /**
     * 获取String中由,分割的各个字段，去除空字段，以ArrayList返回
     *
     * @param retKeys 字符串形式的需要返回的字段名称，由,分割
     * @return ArrayList 包含所有需要返回的key的集合
     */
    public static ArrayList<String> getRetKeys(String retKeys) {
        return getRetKeys(retKeys, ",");
    }

    /**
     * 获取String中由,分割的各个字段，去除空字段，以ArrayList返回
     *
     * @param original 字符串形式的需要返回的字段名称，由,分割
     * @return ArrayList 包含所有需要返回的key的集合
     */
    public static ArrayList<String> getRetKeys(String original, String split) {
        ArrayList<String> arr = new ArrayList<>();
        if (original == null || isBlank(original)) {
            return arr;
        }
        String[] str = original.split(split);
        for (String s : str) {
            if (!isBlank(s)) {
                arr.add(s.trim());
            }
        }
        return arr;
    }

    /**
     * 判断是否为null或空白符或空字符串
     *
     * @param o
     * @return 为空白则true, 否则false
     */
    public static boolean isBlank(Object o) {
        if (o instanceof CharSequence) {
            CharSequence str = (CharSequence) o;
            int strLen;
            if ((strLen = str.length()) == 0) {
                return true;
            }
            for (int i = 0; i < strLen; i++) {
                if ((Character.isWhitespace(str.charAt(i)) == false)) {
                    return false;
                }
            }
            return true;
        } else {
            return (o == null) ? true : isBlank(o.toString());
        }
    }

    /**
     * 判断是否为null或空字符串,空集合,空map,空数组(基本类型的数组也可以识别)
     *
     * @param o
     * @return 为空则true, 否则false
     */
    public static boolean isEmpty(Object o) {
        if (o == null) {
            return true;
        } else if (o instanceof CharSequence) {
            CharSequence str = (CharSequence) o;
            return str.length() == 0;
        } else if (o.getClass().isArray()) {
            return Array.getLength(o) == 0;
        } else if (o instanceof Collection) {
            return ((Collection<?>) o).isEmpty();
        } else if (o instanceof Map) {
            return ((Map<?, ?>) o).isEmpty();
        } else {
            return isEmpty(o.toString());
        }
    }

    /**
     * 判断是否为int32的值，是则返回true，否返回false
     */
    public static boolean isInt32(String str) {
        for (int i = str.length(); --i >= 1; ) {
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        int tmp;
        try {
            tmp = Integer.valueOf(str.trim());
        } catch (Exception e) {
            return false;
        }
        return tmp <= Integer.MAX_VALUE;
    }

    public static Document getDocExcludeFeature(List<String> retKeys) {
        Document fieldFilter = new Document();
        if (!retKeys.contains("all") && !retKeys.contains("ALL") &&
                !retKeys.contains(FEATURE) && !retKeys.contains(FACE_FEATURE)) {
            fieldFilter.put(FEATURE, 0);
            fieldFilter.put(FACE_FEATURE, 0);
        }
        return fieldFilter;
    }

    private StrUtil() {
    }

    public static String objToString(Object obj) {
        if (obj == null) {
            return "null";
        }
        return obj.toString();
    }

}
